<?php

namespace app\api\command;

use think\console\Command;
use think\console\Input;
use think\console\Output;
use think\Db;
use fast\Random;

use app\admin\model\template\Order as OrderModel;
use app\admin\model\NodeDetail as NodeDetailModel;
use app\admin\model\Node as NodeModel;

class AutoCalculateNode extends Command
{

    protected function configure()
    {
        $this->setName('auto_calculate_node')->setDescription('自动节点核算');
    }

    protected function buildTree(array $elements, $parentId = 0)
    {
        $branch = [];
        foreach ($elements as $element) {
            if ($element['pid'] == $parentId) {
                $children = $this->buildTree($elements, $element['id']);
                if ($children) {
                    $element['children'] = $children;
                }
                $branch[] = $element;
            }
        }
        return $branch;
    }

    protected function execute(Input $input, Output $output)
    {
        //创建服务
        $server = new \Swoole\Server('127.0.0.1', 29513);
        $server->set(['enable_coroutine' => false]);

        \Swoole\Timer::tick(3000, function (int $timer_id) {
            
            $orders = OrderModel::where('type', 2)
                                ->where('pay_state', 1)
                                ->where('calculate_status', 0)
                                ->select();

            foreach ($orders as $order) {

                $node = NodeModel::get($order->node_id);
            
                // 产品节点
                $ids = $node->product_children_ids;
                array_push($ids, $node->id);
                $product_node = NodeModel::whereIn('id', $ids)->select();
                $data = NodeDetailModel::whereIn('node_id', $ids)->select();
                $previous = [];
                foreach ($product_node as $item) {
                    $total = 0;
                    foreach ($data as $v) {
                        if ($item->id == $v->node_id) {
                            $total += round((intval($v->factor * 100000) * intval($v->io_value * 10000)) / ($item->produce_amount * 10000 * 100000), 6);
                        }
                    }
                    $previous[$item->id]['pid'] = $item->pid;
                    $previous[$item->id]['total'] = $total;
                    $previous[$item->id]['is_factor'] = 0;
                    $previous[$item->id]['path'] = $item->path;
                    $previous[$item->id]['amount'] = $item->produce_amount;
                }

                // 因子节点
                $node_ids_of_factors = $node->factor_children_ids;
                $factor_data = NodeModel::whereIn('id', $node_ids_of_factors)->select();
                $sum_by_amount_ycl = 0;//原材料
                foreach ($factor_data as $v) {
                    if (!isset($previous[$v->id])) {
                        $previous[$v->id]['pid'] = $v->pid;
                        $previous[$v->id]['total'] = round($v->factor_quotes * $v->factor, 6);
                        $previous[$v->id]['is_factor'] = 1;
                        $previous[$v->id]['path'] = $v->path;
                        $previous[$v->id]['amount'] = 1;
                    } else {
                        $previous[$v->id]['toal'] += round($v->factor_quotes * $v->factor, 6);
                    }

                    //原材料
                    if ($v->node_type == 2) {
                        $sum_by_amount_ycl += round($v->factor_quotes * $v->factor, 6);
                    }
                }
                
                $list = [];
                foreach ($previous as $k1 => $v1) {
                    $list[$k1]['x'] = $v1['total'];
                    foreach ($previous as $v2) {
                        $pre_key = $v1['path'].$k1.'-';
                        if (stripos($v2['path'], $pre_key) !== false) {
                            $list[$k1]['x']  = (float)bcadd($list[$k1]['x'], $v2['total'], 6);
                        }
                    }
                }

                $sum_by_amount = round($list[$node->id]['x'], 5);//总因子,每个
                $sum_by_amount_ycl = round($sum_by_amount_ycl, 5);//原材料因子,每个
                $sum_by_amount_cp = bcsub($sum_by_amount, $sum_by_amount_ycl, 5);//产品因子,每个

                $sum_by_quality = round($sum_by_amount * $node->produce_amount / $node->produce_quality, 5);//总因子,每kg
                $ycl_kg = round($sum_by_amount_ycl * $node->produce_amount / $node->produce_quality, 5);//原材料因子,每kg
                $cp_kg = bcsub($sum_by_quality, $ycl_kg, 5);//产品因子,每kg

                $extra = [
                    'ycl' => (float)$sum_by_amount_ycl,
                    'cp' => (float)$sum_by_amount_cp,
                    'ycl_kg' => (float)$ycl_kg,
                    'cp_kg' => (float)$cp_kg,
                ];

                //总排放量
                $carbon_result = round($sum_by_amount * $node->produce_amount, 2);

                //生成快照
                $children_node_ids = $node->children_ids;
                array_push($children_node_ids, $node->id);
                $tree = NodeModel::field('id,pid,name as topic,is_factor')->whereIn('id', $children_node_ids)->select()->toArray();
                $snapshot = $this->buildTree($tree, $node->pid);

                $result = Db::name('carbon_factor')->insert([
                    'sn' => Random::alnum(14),
                    'name' => $node->level == 1 ? $node->product->name : $node->product->name . '-' . $node->name,
                    'order_id' => $order->id,
                    'user_id' => $node->user_id,
                    'carbon_result' => $carbon_result,
                    'carbon_factor_result' => $sum_by_amount,
                    'carbon_factor_result_kg' => $sum_by_quality,
                    'snapshot' => json_encode($snapshot, JSON_UNESCAPED_UNICODE),
                    'createtime' => time(),
                    'updatetime' => time(),
                    'extra' => json_encode($extra, JSON_UNESCAPED_UNICODE),
                    'nodes_carbon_factor' => json_encode($list)
                ]);

                // 修改订单核算状态
                $order->calculate_status = 1;
                $order->save();
            }
            echo '执行成功' . PHP_EOL;
        });

        //监听数据接收事件。
        $server->on('Receive', function ($server, $fd, $reactor_id, $data) {
            $server->send($fd, "Server: {$data}");
        });

        // 启动服务器
        $server->start();

    }
}
